import java.io.BufferedReader;
import java.io.File;
import java.io.FileInputStream;
import java.io.InputStreamReader;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Scanner;
import javax.swing.*;
import javax.swing.text.*;
import java.awt.*;
import java.io.*;
import java.util.*;
import java.util.List;
/**
 * Description: <br/>
 * date: 2024/4/3 18:10<br/>
 *
 * @author 86136<br />
 * @since JDK 1.8
 */

public class DFS2 {
    private static HashMap<String, Integer> stateTransMap = new HashMap<>();
    private static HashMap<String, String> results = new HashMap<>();
    private static HashSet<String> operator = new HashSet<>();

    private JButton openButton1,openButton2;
    private JTextPane textPane1,textPane2;//,textPane3,textPane4;
    public DFS2(){
        init();
        View();
    }
    public static void main(String[] args){
        new DFS2();
    }

    public void init(){
        stateTransMap.put("0,a", 1);
        stateTransMap.put("0,b", 2);
        stateTransMap.put("0,<", 1);
        stateTransMap.put("0,>", 1);
        stateTransMap.put("0,==", 1);
        stateTransMap.put("0,!=", 1);
        stateTransMap.put("0,<=", 1);
        stateTransMap.put("0,>=", 1);
        stateTransMap.put("0,1", 1);

        stateTransMap.put("1,a", 1);
        stateTransMap.put("1,b", 2);
        stateTransMap.put("1,<", -1);
        stateTransMap.put("1,>", -1);
        stateTransMap.put("1,==", -1);
        stateTransMap.put("1,!=", -1);
        stateTransMap.put("1,<=", -1);
        stateTransMap.put("1,>=", -1);
        stateTransMap.put("1,1", -1);

        stateTransMap.put("2,a", 1);
        stateTransMap.put("2,b", 3);
        stateTransMap.put("2,<", -1);
        stateTransMap.put("2,>", -1);
        stateTransMap.put("2,==", -1);
        stateTransMap.put("2,!=", -1);
        stateTransMap.put("2,<=", -1);
        stateTransMap.put("2,>=", -1);
        stateTransMap.put("2,1", -1);

        stateTransMap.put("3,a", 1);
        stateTransMap.put("3,b", 3);
        stateTransMap.put("3,<", 4);
        stateTransMap.put("3,>", 4);
        stateTransMap.put("3,==", 4);
        stateTransMap.put("3,!=", 4);
        stateTransMap.put("3,<=", 4);
        stateTransMap.put("3,>=", 4);
        stateTransMap.put("3,1", -1);

        stateTransMap.put("4,a", -1);
        stateTransMap.put("4,b", -1);
        stateTransMap.put("4,<", -1);
        stateTransMap.put("4,>", -1);
        stateTransMap.put("4,==", -1);
        stateTransMap.put("4,!=", -1);
        stateTransMap.put("4,<=", -1);
        stateTransMap.put("4,>=", -1);
        stateTransMap.put("4,1", 10);

        stateTransMap.put("10,a", -1);
        stateTransMap.put("10,b", -1);
        stateTransMap.put("10,<", -1);
        stateTransMap.put("10,>", -1);
        stateTransMap.put("10,==", -1);
        stateTransMap.put("10,!=", -1);
        stateTransMap.put("10,<=", -1);
        stateTransMap.put("10,>=", -1);
        stateTransMap.put("10,1", -1);

        operator.add("<");
        operator.add("<=");
        operator.add(">");
        operator.add(">=");
        operator.add("!=");
        operator.add("==");
        operator.add("a");
        operator.add("b");
        operator.add("1");

    }
    public void View(){
        JFrame frame = new JFrame("词法分析器");
        textPane1 = new JTextPane();
        textPane1.setPreferredSize(new Dimension(42 * textPane1.getFontMetrics(textPane1.getFont()).charWidth('W'),
                43 * textPane1.getFontMetrics(textPane1.getFont()).getHeight()));
        textPane2 = new JTextPane();
        textPane2.setPreferredSize(new Dimension(42 * textPane2.getFontMetrics(textPane2.getFont()).charWidth('W'),
                43 * textPane2.getFontMetrics(textPane2.getFont()).getHeight()));


        JScrollPane scrollPane1 = new JScrollPane(textPane1);
        JScrollPane scrollPane2 = new JScrollPane(textPane2);


        openButton1 = new JButton("打开文件");
        openButton2 = new JButton("词法分析");

        openButton1.addActionListener(e -> {
            openFile(textPane1);
        });
        openButton2.addActionListener(e ->{
            try{
                lexicalAnalyzer(textPane1,textPane2);
            }catch (Exception exception){
                exception.printStackTrace();
            }
        });

        JPanel panel = new JPanel();
        panel.setLayout(new GridLayout(1,4));//new FlowLayout(FlowLayout.LEFT)
        panel.add(openButton1);
        panel.add(openButton2);

        JLabel label1 = new JLabel("                       输出结果");
        label1.setFont(new Font("宋体",Font.BOLD,16));
        JLabel label2 = new JLabel("                       文件内容");
        label2.setFont(new Font("宋体",Font.BOLD,16));

        JPanel textpanel = new JPanel();
        textpanel.setLayout(new BoxLayout(textpanel,BoxLayout.Y_AXIS));
        textpanel.add(label2,BorderLayout.NORTH);
        textpanel.add(scrollPane1,BorderLayout.CENTER);

        JPanel resultPanel = new JPanel();
        resultPanel.setLayout(new BoxLayout(resultPanel,BoxLayout.Y_AXIS));
        resultPanel.add(label1,BorderLayout.NORTH);
        resultPanel.add(scrollPane2,BorderLayout.CENTER);


        JPanel panel1 = new JPanel();
        panel1.add(resultPanel);
        JPanel panel2 = new JPanel();
        panel2.add(textpanel);

        Container containPane = frame.getContentPane();
        containPane.add(panel,BorderLayout.NORTH);
        containPane.add(panel2,BorderLayout.WEST);
        containPane.add(panel1,BorderLayout.CENTER);

        frame.setSize(1000,800);
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        frame.setLocationRelativeTo(null);
        frame.setVisible(true);
    }
    private void lexicalAnalyzer(JTextPane textPane1,JTextPane textPane2) throws BadLocationException {
        String[] undetermined = textPane1.getText().replaceAll("\\s*","").split(";");
        results.clear();
        for(String word : undetermined){
            if(move(0, word))
                results.put(word,"可接受");
            else
                results.put(word,"不可接受");
        }
        printTables(textPane2);
    }
    /**
     * 读取并打印选中的文件
     * 使用文件选择器打开文件：
     *
     * JFileChooser fileChooser = new JFileChooser();：这行代码创建一个新的 JFileChooser 对象，允许用户从文件系统中选择一个文件。
     * int value = fileChooser.showOpenDialog(null);：这行代码显示文件选择器对话框并等待用户选择一个文件。null 参数指定文件选择器应相对于当前窗口显示。
     * if (value == JFileChooser.APPROVE_OPTION)：此条件语句检查用户是否单击了文件选择器对话框中的 "打开" 按钮。
     */
    private void openFile(JTextPane textPane){
        Style style = textPane.addStyle("Mystyle",null);
        StyleConstants.setFontSize(style,16);
        StyledDocument doc = textPane.getStyledDocument();

        JFileChooser fileChooser = new JFileChooser();
        int value = fileChooser.showOpenDialog(null);
        if(value == JFileChooser.APPROVE_OPTION){
            File file = fileChooser.getSelectedFile();
            try(BufferedReader reader = new BufferedReader(new FileReader(file))) {
                doc.remove(0,doc.getLength());
                String line;
                while((line = reader.readLine()) != null){
                    doc.insertString(doc.getLength(), line + "\n", style);
                }
            } catch (Exception e) {
                JOptionPane.showMessageDialog(null, "Error open file" + e.getMessage());
            }
        }
    }
    /**
     * 状态转换
     */
    public boolean move(Integer state, String word){
        int i,j;
        for(i = 0;i < word.length();){
            String current = state+",";
            String op = "";
            for(j = 2;j > 0;j--){
                int strIndex = i;
                int endIndex = word.length() < i+j ? word.length() : i+j;
                String temp = word.substring(strIndex,endIndex);
                if(operator.contains(temp))
                {
                    op = temp;
                    i += temp.length();
                    break;
                }
            }
            if(op != ""){
                current += op;//构成完整的key
                state = stateTransMap.get(current);
            }
            else
                return false;
            if(state == -1)
                return false;
        }
        //必须遍历完整个词法单元，正好判定到终态成功才能说此单元成功匹配了
        if(state == 10)
            return true;
        else
            return false;
    }
    /**
     * 打印结果
     */
    public void printTables(JTextPane textPane) throws BadLocationException {
        Style styleBlue,styleRed,styleGreen;
        styleBlue = textPane.addStyle("Blue",null);
        StyleConstants.setForeground(styleBlue,Color.BLUE);
        StyleConstants.setFontSize(styleBlue,16);

        styleRed = textPane.addStyle("Red",null);
        StyleConstants.setForeground(styleRed,Color.RED);
        StyleConstants.setFontSize(styleRed,16);

        styleGreen = textPane.addStyle("Green",null);
        StyleConstants.setForeground(styleGreen,Color.decode("#009966"));//暗绿色
        StyleConstants.setFontSize(styleGreen,16);

        Style style = textPane.addStyle("Mystyle",null);
        StyleConstants.setFontSize(style,16);

        StyledDocument doc = textPane.getStyledDocument();
        //清除上一次的内容
        doc.remove(0, doc.getLength());
        int i = 1;
        for(Map.Entry<String,String> entry : results.entrySet()) {
            try {
                doc.insertString(doc.getLength(),  i + ". ",styleBlue);
                doc.insertString(doc.getLength(), entry.getKey()+": ",style);
                if("不可接受".equals(entry.getValue()))
                    doc.insertString(doc.getLength(), entry.getValue()+"\n",styleRed);
                else
                    doc.insertString(doc.getLength(), entry.getValue()+"\n",styleGreen);
                i++;
            } catch (BadLocationException badLocationException) {
                badLocationException.printStackTrace();
            }
        }

    }
}
